#pragma once

#ifdef WIN32
#include <Windows.h>
#endif

# include <Inventor/SbVec3f.h>
# include <Inventor/nodes/SoBaseColor.h>
# include <Inventor/nodes/SoCoordinate3.h>
# include <Inventor/nodes/SoLightModel.h>
# include <Inventor/nodes/SoMaterial.h>
# include <Inventor/nodes/SoMaterialBinding.h>
# include <Inventor/nodes/SoSeparator.h>
# include <Inventor/nodes/SoSwitch.h>
# include <Inventor/nodes/SoTransform.h>
# include <Inventor/nodes/SoRotation.h>
# include <Inventor/nodes/SoCoordinate3.h>
# include <Inventor/nodes/SoDrawStyle.h>
# include <Inventor/nodes/SoIndexedFaceSet.h>
# include <Inventor/nodes/SoShapeHints.h>
# include <Inventor/nodes/SoPointSet.h>
# include <Inventor/nodes/SoPolygonOffset.h>
# include <Inventor/nodes/SoNormal.h>
# include <Inventor/nodes/SoNormalBinding.h>
#include <Inventor/nodes/SoText3.h>

#include <vector>
#include <Inventor/nodes/SoIndexedFaceSet.h>
#include <Inventor/nodes/SoFaceSet.h>
#include "Inventor/nodes/SoLineSet.h"
#include "GraphTools.h"

namespace DDAGui{
	using namespace std;
    enum DISPLAYMODE{ DISPLAY_ACCUMULATION_DISPLACEMENT , DISPLAY_REALTIME_DISPLACEMENT
		, DISPLAY_REAL_X_DISPLACEMENT , DISPLAY_REAL_Y_DISPLACEMENT , DISPLAY_STRESS};
    extern double maxStress; // the max stress value of all blocks in all steps
    
    class GraphBlock
	{
	public:
		GraphBlock();
		~GraphBlock();

    public:
        inline void setDisplayMode(DISPLAYMODE mode);

	public:
		// whole graph scene node
		SoSeparator* rootGraphBlock;
        SoSwitch* switchDisplayModeNode;

		// block graph
// 		SoSeparator* polygon;
		SoNormal* norm;
		SoNormalBinding* normalBinding;
		SoMaterial* polygonColors;
		SoMaterialBinding* materialBinding;
		SoCoordinate3* polygonCoords;
		SoIndexedFaceSet* faceset;

        // block stress 
        SoBaseColor* stressLineColor;
        SoCoordinate3* stressLineCoords;
        SoLineSet* stressLineset;


		// block boundary lines
        SoBaseColor* lineColor;
		SoCoordinate3* lineCoords;
		SoLineSet* lineset;

	};

    class GraphBoltElemnts
    {
    public:
        GraphBoltElemnts();
        ~GraphBoltElemnts();

    public:
        SoSeparator* rootGraphBolts;
        SoCoordinate3* boltCoords;
        SoLineSet* boltsLineset;
        SoBaseColor* lineColor;

    };


	class GraphMeasuredPoints
	{
	public:
		GraphMeasuredPoints();
		~GraphMeasuredPoints();

//     public:
//         void setMeasuredPointsNum(int num){mpts->resize(num);}
// 
	public:
		SoSeparator* rootGraphMPts;
		SoCoordinate3* meausuredPointsCoords;
		SoLineSet* measuredPointsLineset;
        SoBaseColor* lineColor;

		//vector< vector<MeasuredPoint> >* mpts;
	};
//#define DEBUGScaler
	class Scaler
	{
	private:
		Scaler();
		~Scaler(){}

	public:
		static SoSwitch* getScaler( const std::vector<double>& windowInfo , int scale);
        static inline void setVisible(bool flag)
        {
            if(_rootSwitch)
                _rootSwitch->whichChild= flag?0:SO_SWITCH_NONE;
        }
        static void setScale( double value );
     
    private:
        static SoSeparator* _createScalerBar(const std::vector<double>& windowInfo);
        static SoSeparator* _createTexts(const std::vector<double>& windowInfo);

	private:
        // whole graph scene node
        static SoSwitch* _rootSwitch;
        static SoSeparator* _rootGraphBlock;
        static int scale;
        static vector<SoText3*> texts;
	};

//#define DEBUGSceneGraph
	class SceneGraph
	{
	public:
		SceneGraph();
		~SceneGraph();

	public:
		void resetRootScene(const vector<int> graphSchema , const vector<double> windowInfo );
        inline void setScalerVisible(bool flag)
        {
            Scaler::setVisible(flag);
        }
        void setDisplayMode(DISPLAYMODE mode);

	public:
		GraphBlock *blocks;
        GraphBoltElemnts* bolts;
        int blocksNum;
		SoSeparator* rootScene;
		GraphMeasuredPoints* graphMeasuredPoints;
	};


	class ScaleCalculator
	{
	public:
		virtual double calculateScale(double x1, double y1, double x2, double y2)=0;
	};

	class ScaleCalculator4AccumulatedDisplacement: public ScaleCalculator
	{
	public:
		virtual double calculateScale(double x1, double y1, double x2, double y2);
	};

	class ScaleCalculator4RealTimeDisplacement: public ScaleCalculator
	{
	public:
		virtual double calculateScale(double x1, double y1, double x2, double y2);
	};

	class ScaleCalculator4RealXDisplacement: public ScaleCalculator
	{
	public:
		virtual double calculateScale(double x1, double y1, double x2, double y2);
	};

	class ScaleCalculator4RealYDisplacement: public ScaleCalculator
	{
	public:
		virtual double calculateScale(double x1, double y1, double x2, double y2);
	};

	class BlockUpdatater
	{
    private:
        BlockUpdatater();
        ~BlockUpdatater();
	public:
        static void setScale( double scaleValue);
		static void setScaleCalculator(ScaleCalculator* calc){scaleCalculator = calc;}
		static void reset( FrameData* originalGraph);
        static void update(FrameData* frame , GraphBlock* graphBlock , int blockIdx , DISPLAYMODE mode=DISPLAY_ACCUMULATION_DISPLACEMENT);
        static const vector<double>& getWindowInfo(){ return windowInfo;}
    private:
        static void _updateStress(FrameData* frame , GraphBlock* graphBlock , int blockIdx );
        static void _calcStressCrossCoords( Block& block , vector< pair<double , double> >& coords , double crossHeight );
		static void _calcPolygonColor(FrameData* frame , GraphBlock* graphBlock , int blockIdx , SbColor* colors);
		static void _updatePolygonColor(FrameData* frame , GraphBlock* graphBlock , int blockIdx
			, DISPLAYMODE mode=DISPLAY_ACCUMULATION_DISPLACEMENT);
		static void _updateLines(FrameData* frame , GraphBlock* graphBlock , int blockIdx);
		static bool _ifConcave(const vector<SbVec3f>& pts);
		static int _getVectorUp(const SbVec3f& p1 , const SbVec3f& p2 , const SbVec3f& p3);
		static void _triangulate(vector<SbVec3f>&);
		static void _triangulationCallback(void * v0, void * v1, void * v2, void * cbdata);
		static void _calcColors4ConcavePolygon(const vector<SbVec3f>& pts , SbColor* colors, SbColor* resultColors);
        static void _calcWindowInfoFromFrame();
	private:
		static vector<double> windowInfo;
		static double scale;  // scale for color
		static double accumulatedScale;
		static FrameData* originalGraph;
		static vector<SbVec3f> coords;
		static int tmpCount; // used when triangulation
		static ScaleCalculator* scaleCalculator;
	};

    class BoltElementsUpdater
    {
    private:
        BoltElementsUpdater();
        ~BoltElementsUpdater();
    public:
        static void update(FrameData* frame , SceneGraph* sceneGraph);
    };


    class PointsUpdater
    {
    private:
        PointsUpdater();
        ~PointsUpdater();
    public:
        static void update(FrameData* frame , SceneGraph* sceneGraph);
    };

// 	#define DEBUGFRAMEMAKER

	class FrameMaker
	{
	public:
		FrameMaker(void);
		~FrameMaker(void);

	public:
		bool reset(const FrameData& frame,  const vector<int>& schema);
		bool setRootSceneNode(SoSeparator* node);
        bool updateGraph(FrameData frame , DISPLAYMODE mode = DISPLAY_ACCUMULATION_DISPLACEMENT);
        void removeGraphFromScene();
        void setScale(double value);
		void updateScale(DISPLAYMODE mode = DISPLAY_ACCUMULATION_DISPLACEMENT);

    private:
		SoSeparator* _freeCADrootNode;
		SceneGraph* _rootSceneGraph;
		FrameData _firstFrame;
	};
}// DDAGui